package com.cxyd.modules.wms.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.cxyd.common.constant.enums.wms.*;
import com.cxyd.common.exception.RootException;
import com.cxyd.common.page.PageData;
import com.cxyd.common.service.impl.CrudServiceImpl;
import com.cxyd.common.utils.ConvertUtils;
import com.cxyd.common.utils.ProcResult;
import com.cxyd.common.utils.Result;
import com.cxyd.modules.security.user.SecurityUser;
import com.cxyd.modules.security.user.UserDetail;
import com.cxyd.modules.sys.service.SysUserService;
import com.cxyd.modules.wms.dao.*;
import com.cxyd.modules.wms.dto.AllotTempDTO;
import com.cxyd.modules.wms.dto.OrderDetailDTO;
import com.cxyd.modules.wms.entity.*;
import com.cxyd.modules.wms.service.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.mybatis.spring.SqlSessionTemplate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.RequestBody;

import java.math.BigDecimal;
import java.util.*;

/**
 * 出库明细
 *
 * @author g_Cycle gengruyi01@163.com
 * @since 1.0.0 2023-04-27
 */
@Slf4j
@Service
public class OrderDetailServiceImpl extends CrudServiceImpl<OrderDetailDao, OrderDetailEntity, OrderDetailDTO> implements OrderDetailService {
    private static final Logger logger = LoggerFactory.getLogger(OrderDetailServiceImpl.class);

    private final AllotTempService allotTempService;
    private final SysUserService userService;
    private final OrderDetailDao orderDetailDao;
    private final OrderDao orderDao;
    private final StockDao stockDao;
    private final TaskDao taskDao;
    private final AllotTempDao allotTempDao;
    private final TaskService taskService;
    private final LogWorkService logWorkService;
    private final AllotExecService allotExecService;
    private final SpuDao spuDao;
    private final CommonService commonService;
    private final SqlSessionTemplate sqlSessionTemplate;

    public OrderDetailServiceImpl(AllotTempService allotTempService, SysUserService userService, OrderDetailDao orderDetailDao, OrderDao orderDao, StockDao stockDao, TaskDao taskDao, AllotTempDao allotTempDao, TaskService taskService, LogWorkService logWorkService, AllotExecService allotExecService, SpuDao spuDao, CommonService commonService, SqlSessionTemplate sqlSessionTemplate) {
        this.allotTempService = allotTempService;
        this.userService = userService;
        this.orderDetailDao = orderDetailDao;
        this.orderDao = orderDao;
        this.stockDao = stockDao;
        this.taskDao = taskDao;
        this.allotTempDao = allotTempDao;
        this.taskService = taskService;
        this.logWorkService = logWorkService;
        this.allotExecService = allotExecService;
        this.spuDao = spuDao;
        this.commonService = commonService;
        this.sqlSessionTemplate = sqlSessionTemplate;
    }


    @Override
    public PageData<OrderDetailDTO> page(Map<String, Object> params) {
        //1.查询主单信息
        final IPage<OrderDetailEntity> page = baseDao.selectViewPage(
                getPage(params, "create_date", false),
                getWrapper(params)
        );
        return getPageData(page, OrderDetailDTO.class);
    }

    @Override
    public QueryWrapper<OrderDetailEntity> getWrapper(Map<String, Object> params) {
        Long orderId = ObjectUtils.isNotEmpty(params.get("orderId")) ? Long.parseLong((String) params.get("orderId")) : null;
        Long detailId = ObjectUtils.isNotEmpty(params.get("detailId")) ? Long.parseLong((String) params.get("detailId")) : null;
        String spuNo = (String) params.get("spuNo");
        String spuName = (String) params.get("spuName");
        String detailSt = (String) params.get("detailSt");
        QueryWrapper<OrderDetailEntity> wrapper = new QueryWrapper<>();
        wrapper.eq(ObjectUtils.isNotEmpty(orderId), "order_id", orderId);
        wrapper.eq(ObjectUtils.isNotEmpty(detailId), "detail_id", detailId);
        wrapper.eq(StringUtils.isNotBlank(detailSt), "detail_st", detailSt);
        wrapper.like(StringUtils.isNotBlank(spuNo), "spu_no", spuNo);
        wrapper.like(StringUtils.isNotBlank(spuName), "spu_name", spuName);
        return wrapper;
    }

    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public Result procDetailAutoAllot(Map<String, Object> params) {
        //入参
        Long detailId = Long.parseLong(params.get("detailId").toString());
        Long userId = Long.parseLong(params.get("userId").toString());

        //校验单据是否存在
        OrderDetailEntity orderDetailEntity = orderDetailDao.selectById(detailId);
        if (ObjectUtils.isEmpty(orderDetailEntity)) {
            throw new RootException("出库明细[" + detailId + "]在表中不存在!");
        }
        if (OrderStatusEnum.STOCK_COMPLETED.getCode() == orderDetailEntity.getDetailSt()
                || OrderStatusEnum.OUT_COMPLETE.getCode() == orderDetailEntity.getDetailSt()) {
            throw new RootException("出库明细[" + detailId + "]已完成配货!无需再次配货!");
        }
        Long orderId = orderDetailEntity.getOrderId();
        OrderEntity orderEntity = orderDao.selectById(orderId);
        if (ObjectUtils.isEmpty(orderEntity)) {
            throw new RootException("出库主单[" + orderId + "]在表中不存在!");
        }
        if (OrderStatusEnum.STOCK_COMPLETED.getCode() == orderEntity.getOrderSt()
                || OrderStatusEnum.OUT_COMPLETE.getCode() == orderEntity.getOrderSt()) {
            throw new RootException("出库主单[" + orderId + "]已完成配货!无需再次配货!");
        }
        String spuNo = orderDetailEntity.getSpuNo();
        SpuEntity spuEntity = spuDao.selectOne(new QueryWrapper<SpuEntity>().eq("spu_no", spuNo));
        if (ObjectUtils.isEmpty(spuEntity)) {
            throw new RootException("物料不存在！");
        }
        BigDecimal planQty = orderDetailEntity.getPlanQty().subtract(orderDetailEntity.getBindQty());
        List<StockEntity> stockEntities = stockDao.selectList(new QueryWrapper<StockEntity>()
                .eq("spu_no", spuNo)
                .eq("stock_st", StatusEnum.USABLE.getCode())
                .eq("lock_st", StatusEnum.USABLE.getCode()));

        if (stockEntities.size() == 0) {
            throw new RootException("所需物料[" + spuNo + "]库存暂无可用库存！");
        }
        //通用变量
        String code = "0";
        String msg = "自动配货完成";
        String comment = "自动配货";
        Date dateStart = new Date();
        String work = "OrderDetailController.procDetailAutoAllot";
        LogWorkEntity insertLogWork = new LogWorkEntity();
        insertLogWork.setWorkName(comment);
        insertLogWork.setRelateNo(detailId.toString());
        insertLogWork.setWorkProc(work);
        insertLogWork.setCreator(userId);
        insertLogWork.setCreateDate(dateStart);
        BigDecimal num = BigDecimal.ZERO;
        BigDecimal allotQty;
        BigDecimal bindQty = orderDetailEntity.getBindQty();
        for (StockEntity stockEntity : stockEntities) {
            BigDecimal stockQty = stockEntity.getStockQty();
            if (stockQty.subtract(stockEntity.getLockedQty()).compareTo(BigDecimal.ZERO) <= 0) {
                continue;
            }
            if (stockQty.compareTo(planQty) >= 0) {
                allotQty = planQty;
            } else {
                allotQty = stockQty;
            }
            bindQty = bindQty.add(allotQty);
            //更新库存
            StockEntity updateStock = new StockEntity();
            updateStock.setLockedQty(allotQty);
            updateStock.setStockSt(StatusEnum.DISABLE.getCode());
            updateStock.setComments(comment);
            updateStock.setUpdater(userId);
            updateStock.setUpdateDate(dateStart);
            updateStock.setStockId(stockEntity.getStockId());
            try {
                stockDao.updateById(updateStock);
            } catch (Exception e) {
                logger.info("更新库存失败", e);
                code = "1001";
                msg = e.getMessage();
                insertLogWork.setWorkCode(code);
                insertLogWork.setWorkMsg(msg);
                logWorkService.logWorkInsert(insertLogWork);
                throw new RootException("更新库存失败！");
            }
            //生成任务 proc_wms_task_insert
            TaskEntity insertTask = new TaskEntity();
            insertTask.setTaskType(TaskTypeEnum.OUTBOUND.getCode());
            insertTask.setTaskSubType(TaskSubTypeEnum.CHECK.getCode());
            insertTask.setContNo(stockEntity.getContNo());
            insertTask.setSpuNo(stockEntity.getSpuNo());
            insertTask.setSpuName(spuEntity.getSpuName());
            insertTask.setPlanQty(allotQty);
            insertTask.setActlQty(BigDecimal.ZERO);
            insertTask.setFromPosition(stockEntity.getCurPosition());
            insertTask.setCurrentPosition(stockEntity.getCurPosition());
            insertTask.setMtId(orderEntity.getOrderId());
            insertTask.setMtNo(orderEntity.getOrderNo());
            insertTask.setDetailId(detailId);
            insertTask.setStockId(stockEntity.getStockId());
            insertTask.setCreator(userId);
            insertTask.setUpdater(userId);
            insertTask.setCreateDate(dateStart);
            insertTask.setUpdateDate(dateStart);
            insertTask.setComments(comment);
            try {
                taskService.taskInsert(insertTask);
            } catch (Exception e) {
                logger.info("生成任务失败", e);
                code = "1001";
                msg = e.getMessage();
                insertLogWork.setWorkCode(code);
                insertLogWork.setWorkMsg(msg);
                logWorkService.logWorkInsert(insertLogWork);
                throw new RootException("生成任务失败！");
            }
            num = num.add(allotQty);
            planQty = planQty.subtract(allotQty);
            if (planQty.compareTo(BigDecimal.ZERO) <= 0) {
                logger.info("完成配货");
                break;
            }
        }
        //更新明细配货状态(1-配货中 2-配货完成 3-出库执行 4-完成)
        OrderDetailEntity updateOrderDetail = new OrderDetailEntity();
        if (OrderStatusEnum.OUT_STOCK.getCode() == orderDetailEntity.getDetailSt()) {
            orderDetailEntity.setDetailSt(OrderStatusEnum.OUT_STOCK.getCode());
        } else {
            if (planQty.compareTo(BigDecimal.ZERO) <= 0) {
                updateOrderDetail.setDetailSt(OrderStatusEnum.STOCK_COMPLETED.getCode());
            } else {
                updateOrderDetail.setDetailSt(OrderStatusEnum.IN_STOCK.getCode());
            }
        }
        updateOrderDetail.setBindQty(bindQty);
        updateOrderDetail.setComments(comment);
        updateOrderDetail.setUpdater(userId);
        updateOrderDetail.setUpdateDate(dateStart);
        updateOrderDetail.setDetailId(detailId);
        try {
            orderDetailDao.updateById(updateOrderDetail);
        } catch (Exception e) {
            logger.info("更新明细配货状态失败", e);
            code = "1001";
            msg = e.getMessage();
            insertLogWork.setWorkCode(code);
            insertLogWork.setWorkMsg(msg);
            logWorkService.logWorkInsert(insertLogWork);
            throw new RootException("更新明细配货状态失败！");
        }
        //修改主单状态
        params.put("orderId", orderEntity.getOrderId());
        params.put("comment", comment);
        params.put("userId", userId);
        try {
            commonService.orderStatus(params);
        } catch (Exception e) {
            logger.info("修改主单失败", e);
            code = "1001";
            msg = e.getMessage();
            insertLogWork.setWorkCode(code);
            insertLogWork.setWorkMsg(msg);
            logWorkService.logWorkInsert(insertLogWork);
            throw new RootException("修改主单失败！");
        }
        msg = "单据[" + orderId + "]所需物料[" + orderDetailEntity.getSpuName() + "],数量[" + num.toPlainString() + "]配货成功";
        //记录日志
        insertLogWork.setWorkName(work);
        insertLogWork.setWorkCode(code);
        insertLogWork.setWorkMsg(msg);
        insertLogWork.setWorkProc(work);
        logWorkService.logWorkInsert(insertLogWork);
        return new Result().ok(msg);
    }

    @Override
    public void procDetailManualExec(Map<String, Object> params) {
        //proc_wms_orderDetail_exec
        allotExecService.procOrderDetailAllotExec(params);
    }

    @Override
    public ProcResult procDetailBatchExec(Long[] ids, Long userId) {
        int successQty = 0;
        int errorQty = 0;
        Map<String, Object> map = new HashMap<>();
        map.put("userId", userId);
        if (ids.length > 6) {
            return new ProcResult().result("500", "批量执行数量过多!请控制在[5]条以下");
        }
        for (Long id : ids) {
            map.put("detailId", id);
            try {
                allotExecService.procOrderDetailAllotExec(map);
                successQty += 1;
                logger.info("执行结果:{}", map.get("msg"));
            } catch (Exception e) {
                errorQty += 1;
                logger.info("出库执行失败 detailId={}", id);
            }
        }
        //判断批量执行完成情况
        if (successQty > 0 && errorQty == 0) {
            return new ProcResult().result("0", "批量出库执行[全部]成功!");
        } else if (successQty > 0 && errorQty > 0) {
            return new ProcResult().result("0", "批量出库执行[部分]成功!详情可查阅日志");
        } else {
            return new ProcResult().result("500", "批量出库执行[全部]失败!详情可查阅日志");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public Result procDetailRefund(Map<String, Object> params) {
        //取消配货(明细)
        Long detailId = Long.parseLong(params.get("detailId").toString());
        Long userId = Long.parseLong(params.get("userId").toString());
        Date startDate = new Date();
        String comment = "取消配货";
        String code = "0";
        String msg = "取消配货成功";
        String work = "ContainerApiController.procDetailRefund";
        LogWorkEntity insertLogWork = new LogWorkEntity();
        insertLogWork.setWorkName(comment);
        insertLogWork.setRelateNo(detailId.toString());
        insertLogWork.setWorkProc(work);
        insertLogWork.setCreator(userId);
        insertLogWork.setCreateDate(startDate);
        //校验单据是否存在
        OrderDetailEntity orderDetailEntity = orderDetailDao.selectById(detailId);
        if (ObjectUtils.isEmpty(orderDetailEntity)) {
            throw new RootException("出库明细[" + detailId + "]在表中不存在!");
        }
        if (OrderStatusEnum.STOCK_COMPLETED.getCode() < orderDetailEntity.getDetailSt()
                || OrderStatusEnum.INITIAL.getCode() == orderDetailEntity.getDetailSt()) {
            throw new RootException("出库明细[" + detailId + "]无法取消!");
        }
        Long orderId = orderDetailEntity.getOrderId();
        OrderEntity orderEntity = orderDao.selectById(orderId);
        if (ObjectUtils.isEmpty(orderEntity)) {
            throw new RootException("出库主单[" + orderId + "]在表中不存在!");
        }
        if (OrderStatusEnum.STOCK_COMPLETED.getCode() < orderEntity.getOrderSt()
                || OrderStatusEnum.INITIAL.getCode() == orderEntity.getOrderSt()) {
            throw new RootException("出库主单[" + orderId + "]无法取消!");
        }
        List<TaskEntity> taskEntities = taskDao.selectList(new QueryWrapper<TaskEntity>()
                .eq("detail_id", detailId)
                .eq("task_sub_type", TaskSubTypeEnum.CHECK.getCode())
                .eq("task_st", TaskStEnum.INITIAL.getCode()));
        for (TaskEntity taskEntity : taskEntities) {
            //取消任务
            TaskEntity updateTask = new TaskEntity();
            updateTask.setTaskSt(TaskStEnum.CANCEL.getCode());
            updateTask.setComments(comment);
            updateTask.setUpdater(userId);
            updateTask.setTaskId(taskEntity.getTaskId());
            updateTask.setUpdateDate(startDate);
            try {
                taskDao.updateById(updateTask);
            } catch (Exception e) {
                logger.info("取消任务失败", e);
                code = "1001";
                msg = e.getMessage();
                insertLogWork.setWorkCode(code);
                insertLogWork.setWorkMsg(msg);
                logWorkService.logWorkInsert(insertLogWork);
                throw new RootException("取消任务失败！");
            }
            StockEntity stockEntity = stockDao.selectById(taskEntity.getStockId());
            //释放库存
            BigDecimal lockedQty = stockEntity.getLockedQty().subtract(taskEntity.getPlanQty());
            StockEntity updateStock = new StockEntity();
            updateStock.setLockedQty(lockedQty);
            updateStock.setComments(comment);
            if (lockedQty.compareTo(BigDecimal.ZERO) == 0) {
                updateStock.setStockSt(StatusEnum.USABLE.getCode());
            }
            updateStock.setUpdater(userId);
            updateStock.setUpdateDate(startDate);
            updateStock.setStockId(taskEntity.getStockId());
            try {
                stockDao.updateById(updateStock);
            } catch (Exception e) {
                logger.info("释放库存失败", e);
                code = "1001";
                msg = e.getMessage();
                insertLogWork.setWorkCode(code);
                insertLogWork.setWorkMsg(msg);
                logWorkService.logWorkInsert(insertLogWork);
                throw new RootException("释放库存失败！");
            }

        }
        //更新明细配货状态
        OrderDetailEntity updateOrderDetail = new OrderDetailEntity();
        updateOrderDetail.setBindQty(BigDecimal.ZERO);
        updateOrderDetail.setDetailSt(OrderStatusEnum.INITIAL.getCode());
        updateOrderDetail.setUpdater(userId);
        updateOrderDetail.setUpdateDate(startDate);
        updateOrderDetail.setDetailId(detailId);
        try {
            orderDetailDao.updateById(updateOrderDetail);
        } catch (Exception e) {
            logger.info("更新明细配货状态失败", e);
            code = "1001";
            msg = e.getMessage();
            insertLogWork.setWorkCode(code);
            insertLogWork.setWorkMsg(msg);
            logWorkService.logWorkInsert(insertLogWork);
            throw new RootException("更新明细配货状态失败！");
        }
        //修改主单状态
        params.put("orderId", orderEntity.getOrderId());
        params.put("comment", comment);
        params.put("userId", userId);
        try {
            commonService.orderStatus(params);
        } catch (Exception e) {
            logger.info("修改主单失败", e);
            code = "1001";
            msg = e.getMessage();
            insertLogWork.setWorkCode(code);
            insertLogWork.setWorkMsg(msg);
            logWorkService.logWorkInsert(insertLogWork);
            throw new RootException("修改主单失败！");
        }
        //记录日志
        msg = "单据[" + orderId + "]所需物料[" + orderDetailEntity.getSpuName() + "],数量[" + orderDetailEntity.getPlanQty() + "]取消配货成功";
        insertLogWork.setWorkCode(code);
        insertLogWork.setWorkMsg(msg);
        logWorkService.logWorkInsert(insertLogWork);
        return new Result().ok(msg);
    }

    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public Result procDetailManualAllot(List<AllotTempDTO> dtoList, Long userId) {
        if (dtoList.isEmpty()) {
            throw new RootException("请选择需要配货的数据");
        }
        //获取uid
        UUID uuid = UUID.randomUUID();
        //将数据批量新增至[wms_allot_temp]表中
        List<AllotTempEntity> entities = ConvertUtils.sourceToTarget(dtoList, AllotTempEntity.class);
        entities.stream().forEach(item -> item.setUid(uuid.toString()));
        allotTempService.insertBatch(entities);

        List<AllotTempEntity> allotTempEntityList = allotTempDao.selectList(new QueryWrapper<AllotTempEntity>().eq("uid", uuid.toString()));
        if (CollectionUtils.isEmpty(allotTempEntityList)) {
            throw new RootException("配货清单中无数据!");
        }
        Long detailId = allotTempEntityList.get(0).getDetailId();
        Date startDate = new Date();
        String comment = "手动配货";
        String code = "0";
        String msg = "手动配货成功";
        String work = "ContainerApiController.procDetailManualAllot";
        LogWorkEntity insertLogWork = new LogWorkEntity();
        insertLogWork.setWorkName(comment);
        insertLogWork.setRelateNo(detailId.toString());
        insertLogWork.setWorkProc(work);
        insertLogWork.setCreator(userId);
        insertLogWork.setCreateDate(startDate);

        //校验单据是否存在
        OrderDetailEntity orderDetailEntity = orderDetailDao.selectById(detailId);
        if (ObjectUtils.isEmpty(orderDetailEntity)) {
            throw new RootException("出库明细[" + detailId + "]在表中不存在!");
        }
        if (OrderStatusEnum.STOCK_COMPLETED.getCode() == orderDetailEntity.getDetailSt()
                || OrderStatusEnum.OUT_COMPLETE.getCode() == orderDetailEntity.getDetailSt()) {
            throw new RootException("出库明细[" + detailId + "]已完成配货!无需再次配货!");
        }
        Long orderId = orderDetailEntity.getOrderId();
        OrderEntity orderEntity = orderDao.selectById(orderId);
        if (ObjectUtils.isEmpty(orderEntity)) {
            throw new RootException("出库主单[" + orderId + "]在表中不存在!");
        }
        if (OrderStatusEnum.STOCK_COMPLETED.getCode() == orderEntity.getOrderSt()
                || OrderStatusEnum.OUT_COMPLETE.getCode() == orderEntity.getOrderSt()) {
            throw new RootException("出库主单[" + orderId + "]已完成配货!无需再次配货!");
        }
        SpuEntity spuEntity = spuDao.selectOne(new QueryWrapper<SpuEntity>().eq("spu_no", orderDetailEntity.getSpuNo()));
        if (ObjectUtils.isEmpty(spuEntity)) {
            throw new RootException("物料不存在！");
        }
        BigDecimal reduce = allotTempEntityList.stream().map(AllotTempEntity::getAllotQty).reduce(BigDecimal.ZERO, BigDecimal::add);
        if (orderDetailEntity.getBindQty().add(reduce).compareTo(orderDetailEntity.getPlanQty()) > 0) {
            throw new RootException("分配物料数量多余需求数量！");
        }
        BigDecimal num = BigDecimal.ZERO;
        for (AllotTempEntity allotTempEntity : allotTempEntityList) {
            Long stockId = allotTempEntity.getStockId();
            BigDecimal allotQty = allotTempEntity.getAllotQty();
            if (allotQty.compareTo(BigDecimal.ZERO) <= 0) {
                code = "1001";
                msg = "出库明细[" + detailId + "]需求库存[" + stockId + "]的需求数量为0!";
                logger.info(msg);
                insertLogWork.setWorkCode(code);
                insertLogWork.setWorkMsg(msg);
                logWorkService.logWorkInsert(insertLogWork);
                throw new RootException(msg);
            }
            StockEntity stockEntity = stockDao.selectById(stockId);
            if (ObjectUtils.isEmpty(stockEntity)) {
                code = "1001";
                msg = "库存[" + stockId + "]不存在!";
                logger.info(msg);
                insertLogWork.setWorkCode(code);
                insertLogWork.setWorkMsg(msg);
                logWorkService.logWorkInsert(insertLogWork);
                throw new RootException(msg);
            }
            if (StatusEnum.USABLE.getCode() != stockEntity.getLockSt()) {
                code = "1001";
                msg = "库存[" + stockId + "]已被冻结!不可用";
                logger.info(msg);
                insertLogWork.setWorkCode(code);
                insertLogWork.setWorkMsg(msg);
                logWorkService.logWorkInsert(insertLogWork);
                throw new RootException(msg);
            }
            if (!stockEntity.getSpuNo().equals(orderDetailEntity.getSpuNo())) {
                code = "1001";
                msg = "库存[" + stockId + "]与需求的型材编号不一致";
                logger.info(msg);
                insertLogWork.setWorkCode(code);
                insertLogWork.setWorkMsg(msg);
                logWorkService.logWorkInsert(insertLogWork);
                throw new RootException(msg);
            }
            BigDecimal usableQty = stockEntity.getStockQty().subtract(stockEntity.getLockedQty());
            if (allotQty.compareTo(usableQty) > 0) {
                code = "1001";
                msg = "库存[" + stockId + "不足!需求[" + allotQty + "]可用[" + usableQty + "]";
                logger.info(msg);
                insertLogWork.setWorkCode(code);
                insertLogWork.setWorkMsg(msg);
                logWorkService.logWorkInsert(insertLogWork);
                throw new RootException(msg);
            }
            //修改出库明细
            OrderDetailEntity updateOrderDetail = new OrderDetailEntity();
            updateOrderDetail.setBindQty(orderDetailEntity.getBindQty().add(allotQty));
            updateOrderDetail.setDetailId(detailId);
            updateOrderDetail.setUpdater(userId);
            updateOrderDetail.setUpdateDate(startDate);
            updateOrderDetail.setComments(comment);
            if (OrderStatusEnum.OUT_STOCK.getCode() == orderDetailEntity.getDetailSt()) {
                orderDetailEntity.setDetailSt(OrderStatusEnum.OUT_STOCK.getCode());
            } else {
                if (updateOrderDetail.getBindQty().compareTo(orderDetailEntity.getPlanQty()) == 0) {
                    updateOrderDetail.setDetailSt(OrderStatusEnum.STOCK_COMPLETED.getCode());
                } else {
                    updateOrderDetail.setDetailSt(OrderStatusEnum.IN_STOCK.getCode());
                }
            }
            try {
                orderDetailDao.updateById(updateOrderDetail);
            } catch (Exception e) {
                logger.info("修改出库明细失败", e);
                code = "1001";
                msg = e.getMessage();
                insertLogWork.setWorkCode(code);
                insertLogWork.setWorkMsg(msg);
                logWorkService.logWorkInsert(insertLogWork);
                throw new RootException("修改出库明细失败！");
            }
            //修改主单状态
            Map<String, Object> map = new HashMap<>();
            map.put("userId", userId);
            map.put("orderId", orderEntity.getOrderId());
            map.put("comment", comment);
            try {
                commonService.orderStatus(map);
            } catch (Exception e) {
                logger.info("修改主单失败", e);
                code = "1001";
                msg = e.getMessage();
                insertLogWork.setWorkCode(code);
                insertLogWork.setWorkMsg(msg);
                logWorkService.logWorkInsert(insertLogWork);
                throw new RootException("修改主单失败！");
            }
            //修改库存
            StockEntity updateStock = new StockEntity();
            updateStock.setStockSt(StatusEnum.DISABLE.getCode());
            updateStock.setStockId(stockId);
            updateStock.setUpdater(userId);
            updateStock.setComments(comment);
            updateStock.setUpdateDate(startDate);
            updateStock.setLockedQty(stockEntity.getLockedQty().add(allotQty));
            try {
                stockDao.updateById(updateStock);
            } catch (Exception e) {
                logger.info("修改库存失败", e);
                code = "1001";
                msg = e.getMessage();
                insertLogWork.setWorkCode(code);
                insertLogWork.setWorkMsg(msg);
                logWorkService.logWorkInsert(insertLogWork);
                throw new RootException("修改库存失败！");
            }
            //生成任务
            TaskEntity insertTask = new TaskEntity();
            insertTask.setTaskType(TaskTypeEnum.OUTBOUND.getCode());
            insertTask.setTaskSubType(TaskSubTypeEnum.CHECK.getCode());
            insertTask.setContNo(stockEntity.getContNo());
            insertTask.setSpuNo(stockEntity.getSpuNo());
            insertTask.setSpuName(spuEntity.getSpuName());
            insertTask.setPlanQty(allotQty);
            insertTask.setActlQty(BigDecimal.ZERO);
            insertTask.setFromPosition(stockEntity.getCurPosition());
            insertTask.setCurrentPosition(stockEntity.getCurPosition());
            insertTask.setMtId(orderEntity.getOrderId());
            insertTask.setMtNo(orderEntity.getOrderNo());
            insertTask.setDetailId(detailId);
            insertTask.setStockId(stockId);
            insertTask.setComments(comment);
            insertTask.setCreator(userId);
            insertTask.setCreateDate(startDate);
            insertTask.setUpdater(userId);
            insertTask.setUpdateDate(startDate);
            try {
                taskService.taskInsert(insertTask);
            } catch (Exception e) {
                logger.info("生成任务失败", e);
                code = "1001";
                msg = e.getMessage();
                insertLogWork.setWorkCode(code);
                insertLogWork.setWorkMsg(msg);
                logWorkService.logWorkInsert(insertLogWork);
                throw new RootException("生成任务失败！");
            }
            orderDetailEntity = orderDetailDao.selectById(detailId);
            orderEntity = orderDao.selectById(orderDetailEntity.getOrderId());
            num = num.add(allotQty);
        }
        msg = "单据[" + orderId + "]所需物料[" + spuEntity.getSpuName() + "],数量[" + num.toPlainString() + "]配货成功";
        //记录日志 proc_wms_log_insert
        insertLogWork.setWorkCode(code);
        insertLogWork.setWorkMsg(msg);
        logWorkService.logWorkInsert(insertLogWork);
        return new Result().ok(msg);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void save(OrderDetailDTO dto) {
        OrderDetailEntity entity = ConvertUtils.sourceToTarget(dto, OrderDetailEntity.class);
        insert(entity);

        UserDetail user = SecurityUser.getUser();
        final Map<String, Object> map = new HashMap<>();
        map.put("detailId", entity.getDetailId());
        map.put("userId", user.getId());

        try {
            this.procDetailAutoAllot(map);
        } catch (Exception e) {
            // 直接修改原entity对象，然后更新
            entity.setComments("自动配货失败: " + e.getMessage());
            updateById(entity); // 使用同一个entity对象
            log.warn("自动配货失败, detailId: {}", entity.getDetailId(), e);
        }
    }

    @Override
    public int batchSave(List<OrderDetailEntity> details) {
        return baseDao.batchSaveOrderDetails(details);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(OrderDetailDTO dto) {
        OrderDetailEntity entity = ConvertUtils.sourceToTarget(dto, OrderDetailEntity.class);
        //明细单状态必须为初始状态
        if (entity.getDetailSt() != 0) {
            throw new RootException("只有[初始]状态明细单才可以修改数量");
        }
        //entity.setUpdateDate(new DateTime());
        //entity.setUpdater(user.getId());
        updateById(entity);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(@RequestBody Long[] ids) {
        for (int i = 0; i < ids.length; i++) {
            deleteDetailById(ids[i]);
        }
    }

    public void deleteDetailById(Long id) {
        OrderDetailEntity entity = baseDao.selectById(id);
        //判断明细状态是否为初始状态
        if (entity.getDetailSt() != 0) {
            throw new RootException("只有[初始]状态明细单才可以删除");
        }
        //删除
        baseDao.deleteById(id);
    }

    @Override
    public List<OrderDetailEntity> findByOrderId(Long orderId) {
        final QueryWrapper<OrderDetailEntity> wrapper = new QueryWrapper<>();
        wrapper.eq(orderId != null, "order_id", orderId);
        return baseDao.selectList(wrapper);
    }
}